=begin pod

=TITLE class IO::Spec::Win32

=SUBTITLE Platform specific operations on file and directory paths for Windows

    class IO::Spec::Win32 is IO::Spec { }

Objects of this class are not used directly but as a sub-class specific to
the platform perl is running on via the C<$*SPEC> variable which will contain
an object of the appropriate type

B<NOTE:> the C<IO::Spec::*> classes provide low-level path operations. Unless
you're creating your own high-level path manipulation routines, you don't
need to use C<IO::Spec::*>. Use L«C<IO::Path>|/type/IO::Path» instead.

B<NOTE2:> no special validation is done by these classes (e.g. check whether
path contains a null character). It is the job of higher-level classes, like
L«C<IO::Path>|/type/IO::Path», to do that.

=head1 Methods

=head2 method basename

Defined as:

    method basename(Str:D $path --> Str:D)

Takes a path as a string and returns a possibly-empty portion after the last
slash or backslash:

    IO::Spec::Win32.basename("foo/bar/") .perl.say; # OUTPUT: «""␤»
    IO::Spec::Win32.basename("foo/bar\\").perl.say; # OUTPUT: «""␤»
    IO::Spec::Win32.basename("foo/bar/.").perl.say; # OUTPUT: «"."␤»
    IO::Spec::Win32.basename("foo/bar")  .perl.say; # OUTPUT: «"bar"␤»

=head2 method canonpath

Defined as:

    method canonpath(Str() $path, :$parent --> Str:D)

Returns a string that is a canonical representation of C<$path>. If C<:$parent>
is set to true, will also clean up references to parent directories. B<NOTE:>
the routine does not access the filesystem.

    IO::Spec::Win32.canonpath("C:/foo//../bar/../ber").say;
    # OUTPUT: «C:\foo\..\bar\..\ber␤»

    IO::Spec::Win32.canonpath("C:/foo///./../bar/../ber").say;
    # OUTPUT: «C:\foo\..\bar\..\ber␤»

    IO::Spec::Win32.canonpath("C:/foo///./../bar/../ber", :parent).say;
    # OUTPUT: «C:\ber␤»

=head2 method catdir

Defined as:

    method catdir (*@parts --> Str:D)

Concatenates multiple path fragments and returns the canonical representation
of the resultant path as a string. The C<@parts> are L«C<Str>|/type/Str» objects
and are allowed to contain path separators.

    IO::Spec::Win32.catdir(<foo/bar ber perl>).say;
    # OUTPUT: «foo\bar\ber\perl␤»

=head2 method catfile

Alias for L«C<catdir>|/routine/catdir».

=head2 method catpath

Defined as:

    method catpath (Str:D $volume, Str:D $dir, Str:D $file --> Str:D)

Concatenates a path from given volume, a chain of directories, and file.
An empty string can be given for any of the three arguments. No attempt to
make the path canonical is made. Use L«C<canonpath>|/routine/canonpath» for
that purpose.

    IO::Spec::Win32.catpath('C:', '/some/dir', 'foo.txt').say;
    # OUTPUT: «C:/some/dir\foo.txt␤»

    IO::Spec::Win32.catpath('C:', '/some/dir', '').say;
    # OUTPUT: «C:/some/dir␤»

    IO::Spec::Win32.catpath('', '/some/dir', 'foo.txt').say;
    # OUTPUT: «/some/dir\foo.txt␤»

    IO::Spec::Win32.catpath('E:', '', 'foo.txt').say;
    # OUTPUT: «E:foo.txt␤»

=head2 method devnull

Defined as:

    method devnull(--> Str:D)

Returns the string C<"nul"> representing the
L<"Null device"|https://en.wikipedia.org/wiki/Null_device>:

=for code
$*SPEC.devnull.IO.spurt: "foo bar baz";

=head2 method dir-sep

Defined as:

    method dir-sep(--> Str:D)

Returns the string C<｢\｣> representing canonical directory separator character.

=for code
IO::Spec::Win32.dir-sep.say; # OUTPUT: «\␤»

=head2 method is-absolute

Defined as:

    method is-absolute(Str:D $path --> Bool:D)

Returns C<True> if the C<$path> starts with a slash (C<"/">) or backslash
(C<"\">), even if they have combining character on them, optionally preceded by
a volume:

    say IO::Spec::Win32.is-absolute: "/foo";        # OUTPUT: «True␤»
    say IO::Spec::Win32.is-absolute: "/\x[308]foo"; # OUTPUT: «True␤»
    say IO::Spec::Win32.is-absolute: ｢C:\foo｣;      # OUTPUT: «True␤»
    say IO::Spec::Win32.is-absolute: "bar";         # OUTPUT: «False␤»

=head2 method join

=begin comment

  XXX TODO: I'm not exactly sure *why* we have .join along with .catpath and
  in what usecases join's *slightly* different behaviour is useful

=end comment

Defined as:

    method join (Str:D $volume, Str:D $dir, Str:D $file --> Str:D)

Similar to L«C<catpath>|/routine/catpath», takes two path fragments and
concatenates them, adding or removing a path separator, if necessary, except
it will return just C<$file> if both C<$dir> and C<$file> are string C<'/'>
or if C<$dir> is the string C<'.'>. The first argument is ignored (it exists to
maintain consistent interface with other C<IO::Spec> types for systems that have
volumes).

    IO::Spec::Win32.join('C:', '/some/dir', 'foo.txt').say;
    # OUTPUT: «C:/some/dir\and/more␤»

    IO::Spec::Win32.join('C:', '.', 'foo.txt').say;
    # OUTPUT: «C:foo.txt␤»

    IO::Spec::Win32.join('C:', ｢\｣, '/').say;
    # OUTPUT: «C:\␤»

    IO::Spec::Win32.join('//server/share', ｢\｣, '/').say;
    # OUTPUT: «//server/share␤»

    IO::Spec::Win32.join('E:', '', 'foo.txt').say;
    # OUTPUT: «E:foo.txt␤»

=head2 method path

Defined as:

    method path(--> Seq:D)

Splits the value of C«%*ENV<PATH>» (or C«%*ENV<Path>» if the former is not set)
on semicolons (C<";">) and returns a L<Seq> with each of the resultant
parts, always adding element C<"."> to the head. Removes all double
quotes (C<">) it finds.

    %*ENV<PATH> = 'foo;"bar"/"ber"';
    IO::Spec::Win32.path.perl.say; # OUTPUT: «(".", "foo", "bar/ber").Seq␤»

=head2 method rel2abs

Defined as:

    method rel2abs(Str() $path, $base = $*CWD --> Str:D)

Returns a string representing C<$path> converted to absolute path, based at
C<$base>, which defaults to C<$*CWD>. If C<$base> is not an absolute path,
it will be made absolute relative to C<$*CWD>, unless C<$*CWD> and C<$base>
are the same.

=begin code
say $*CWD;                                   # OUTPUT: «"C:\Users\camelia".IO␤»

say IO::Spec::Win32.rel2abs: 'foo';          # OUTPUT: «C:\Users\camelia\foo␤»
say IO::Spec::Win32.rel2abs: './';           # OUTPUT: «C:\Users\camelia␤»
say IO::Spec::Win32.rel2abs: 'foo/../../';   # OUTPUT: «C:\Users\camelia\foo\..\..␤»
say IO::Spec::Win32.rel2abs: '/foo/';        # OUTPUT: «C:\foo␤»

say IO::Spec::Win32.rel2abs: 'foo', 'bar';   # OUTPUT: «C:\Users\camelia\bar\foo␤»
say IO::Spec::Win32.rel2abs: './', '/bar';   # OUTPUT: «\bar␤»
say IO::Spec::Win32.rel2abs: '/foo/', 'bar'; # OUTPUT: «C:\foo␤»

say IO::Spec::Win32.rel2abs: 'foo/../../', 'bar';
# OUTPUT: «C:\Users\camelia\bar\foo\..\..␤»
=end code

=head2 method rootdir

Defined as:

    method rootdir(--> Str:D)

Returns string C<｢\｣>, representing root directory.

=head2 method split

Defined as:

    method split(Cool:D $path --> List:D)

Splits the given C<$path> into "volume", "dirname", and "basename" and
returns the result as a L<List> of three L<Pairs|/type/Pair>, in that order.
The "volume" is always an empty string and exists for consistency with other
L<IO::Spec> classes.

=begin code
IO::Spec::Win32.split('C:/foo/bar.txt').perl.say;
# OUTPUT: «(:volume("C:"), :dirname("/foo"), :basename("bar.txt"))␤»

IO::Spec::Win32.split('/foo/').perl.say;
# OUTPUT: «(:volume(""), :dirname("/"), :basename("foo"))␤»

IO::Spec::Win32.split('///').perl.say;
# OUTPUT: «(:volume(""), :dirname("/"), :basename("\\"))␤»

IO::Spec::Win32.split('./').perl.say;
# OUTPUT: «(:volume(""), :dirname("."), :basename("."))␤»

IO::Spec::Win32.split('.').perl.say;
# OUTPUT: «(:volume(""), :dirname("."), :basename("."))␤»

IO::Spec::Win32.split('').perl.say;
# OUTPUT: «(:volume(""), :dirname(""), :basename(""))␤»
=end code

=head2 method splitdir

Defined as:

    method splitdir(Cool:D $path --> List:D)

Splits the given C<$path> on slashes and backslashes.

=begin code
IO::Spec::Win32.splitdir('C:\foo/bar.txt').perl.say;
# OUTPUT: «("C:", "foo", "bar.txt")␤»

IO::Spec::Win32.splitdir('/foo/').perl.say;
# OUTPUT: «("", "foo", "")␤»

IO::Spec::Win32.splitdir('///').perl.say;
# OUTPUT: «("", "", "", "")␤»

IO::Spec::Win32.splitdir('./').perl.say;
# OUTPUT: «(".", "")␤»

IO::Spec::Win32.splitdir('.').perl.say;
# OUTPUT: «(".",)␤»

IO::Spec::Win32.splitdir('').perl.say;
# OUTPUT: «("",)␤»
=end code

=head2 method splitpath

Defined as:

    method splitpath(Cool:D $path, :$nofile --> List:D)

Splits the given C<$path> into a list of 3 strings: volume,
dirname, and file. The volume is always an empty string, returned for API
compatibility with other L<IO::Spec> types. If C<:$nofile> named argument is
set to C<True>, the content of the file string is undefined and should be
ignored; this is a means to get a performance boost, as implementations may use
faster code path when file is not needed.

=begin code
IO::Spec::Win32.splitpath('C:\foo/bar.txt').perl.say;
# OUTPUT: «("C:", "\\foo/", "bar.txt")␤»

IO::Spec::Win32.splitpath('C:\foo/bar.txt', :nofile).perl.say;
# OUTPUT: «("C:", "\\foo/bar.txt", "")␤»

IO::Spec::Win32.splitpath('/foo/').perl.say;
# OUTPUT: «("", "/foo/", "")␤»

IO::Spec::Win32.splitpath('/foo/', :nofile).perl.say;
# OUTPUT: «("", "/foo/", "")␤»

IO::Spec::Win32.splitpath('///').perl.say;
# OUTPUT: «("", "///", "")␤»

IO::Spec::Win32.splitpath('./').perl.say;
# OUTPUT: «("", "./", "")␤»

IO::Spec::Win32.splitpath('.').perl.say;
# OUTPUT: «("", "", ".")␤»

IO::Spec::Win32.splitpath('').perl.say;
# OUTPUT: «("", "", "")␤»
=end code

=head2 method tmpdir

Defined as:

        method tmpdir(--> IO::Path:D)

Attempts to locate a system's temporary directory by checking several typical directories and environmental variables. Uses current directory if no suitable directories are found.

=end pod

# vim: expandtab shiftwidth=4 ft=perl6
